<template>
<article class="page page-matrix-decrypt container">
	<h4 class="text-center">矩阵加密解密（数字坐标）</h4>
	<form class="content">
		<div class="row panel-1">
			<div class="col-6">
				<fieldset>
					<legend>矩阵加密</legend>
					<div class="form-group row">
						<label class="col-2 col-form-label">原 文</label>
						<div class="col-9">
							<input type="text" class="form-control" v-model="originalText" placeholder="请输入要加密的文字">
						</div>
					</div>
					<div class="form-group row">
						<label class="col-2 col-form-label">长 度</label>
						<div class="col-9">
							<input type="text" class="form-control" v-model="originalTextLen" placeholder="字符串长度" readonly="readonly">
						</div>
					</div>
					<div class="form-group row">
						<label class="col-2 col-form-label">操 作</label>
						<div class="col-9">
							<x-button type="primary" block @click="encrypt">加 密</x-button>
						</div>
					</div>
					<div class="form-group row">
						<label class="col-2 col-form-label">结 果</label>
						<div class="col-9">
							<input type="text" class="form-control" v-model="encryption">
						</div>
					</div>
				</fieldset>
			</div>
			<div class="col-6">
				<fieldset>
					<legend>矩阵解密</legend>
					<div class="form-group row">
						<label class="col-2 col-form-label">密 文</label>
						<div class="col-9">
							<input type="text" class="form-control" v-model="cipherText" placeholder="请输入密文">
						</div>
					</div>
					<div class="form-group row">
						<label class="col-2 col-form-label">长 度</label>
						<div class="col-9">
							<input type="text" class="form-control" v-model="cipherTextLen" placeholder="密文长度" readonly="readonly">
						</div>
					</div>
					<div class="form-group row">
						<label class="col-2 col-form-label">操 作</label>
						<div class="col-9">
							<x-button type="primary" block @click="decrypt">解 密</x-button>
						</div>
					</div>
					<div class="form-group row">
						<label class="col-2 col-form-label">结 果</label>
						<div class="col-9">
							<input type="text" class="form-control" v-model="deciphered">
						</div>
					</div>
				</fieldset>
			</div>
		</div>
		<fieldset class="panel-2">
			<legend>加密规则</legend>
			<div class="alert alert-secondary" role="alert">
				<div>1、<span class="btn-link" @click="getMatrix55">5×5矩阵加密</span> 源于《闪电侠14》，为默认选项；</div>
				<div>2、<span class="btn-link" @click="getMatrix94">9×4矩阵加密</span> 为手机键盘加密，是流传比较广泛的一种加密方式；</div>
				<div>3、为便于灵活应对不同的矩阵加密，本工具也同时支持自定义矩阵加密（最大支持35×35）。</div>
			</div>
			<div class="form-group row">
				<div class="col-3">
					<div class="input-group">
						<div class="input-group-prepend">
							<span class="input-group-text">行 数</span>
						</div>
						<input type="text" class="form-control" v-model.trim="rowspan_">
					</div>
				</div>
				<div class="col-3">
					<div class="input-group">
						<div class="input-group-prepend">
							<span class="input-group-text">列 数</span>
						</div>
						<input type="text" class="form-control" v-model.trim="colspan_">
					</div>
				</div>
				<div class="col-6 text-right">
					<div class="btn-group" role="group">
						<button type="button" class="btn btn-secondary" @click="createTable">创建表格</button>
						<button type="button" class="btn btn-secondary" @click="changeOptions" :disabled="disableSetting">配置参数</button>
						<button type="button" class="btn btn-secondary" @click="updateOptions" :disabled="disableUpdate">更新配置</button>
					</div>
				</div>
			</div>
			<table v-if="colspan && rowspan" class="table table-bordered" :class="{'table-more': colspan >= 19}">
				<tbody>
					<tr>
						<th></th>
						<th v-for="col in colspan" :key="`col_${col}`">{{col | numberFilter}}</th>
					</tr>
					<tr v-for="row in rowspan" :key="`row_${row}`">
						<th>{{row | numberFilter}}</th>
						<td v-for="col in colspan" :key="`td_${row}_${col}`">
							<input type="text" class="form-control" v-model="tableData[`${row}_${col}`]" :readonly="readonly">
						</td>
					</tr>
				</tbody>
			</table>
		</fieldset>
	</form>
</article>
</template>

<script>
const matrix55 = {
	'1_1': 'A', '1_2': 'B', '1_3': 'C/K', '1_4': 'D', '1_5': 'E',
	'2_1': 'F', '2_2': 'G', '2_3': 'H', '2_4': 'I', '2_5': 'J',
	'3_1': 'L', '3_2': 'M', '3_3': 'N', '3_4': 'O', '3_5': 'P',
	'4_1': 'Q', '4_2': 'R', '4_3': 'S', '4_4': 'T', '4_5': 'U',
	'5_1': 'V', '5_2': 'W', '5_3': 'X', '5_4': 'Y', '5_5': 'Z',
}
const matrix94 = {
	'1_1': '', '1_2': '', '1_3': '', '1_4': '',
	'2_1': 'a', '2_2': 'b', '2_3': 'c', '2_4': '',
	'3_1': 'd', '3_2': 'e', '3_3': 'f', '3_4': '',
	'4_1': 'g', '4_2': 'h', '4_3': 'i', '4_4': '',
	'5_1': 'j', '5_2': 'k', '5_3': 'l', '5_4': '',
	'6_1': 'm', '6_2': 'n', '6_3': 'o', '6_4': '',
	'7_1': 'p', '7_2': 'q', '7_3': 'r', '7_4': 's',
	'8_1': 't', '8_2': 'u', '8_3': 'v', '8_4': '',
	'9_1': 'w', '9_2': 'x', '9_3': 'y', '9_4': 'z',
}

export default {
	name: 'matrix-decrypt',
	data () {
		return {
			originalText: '',
			encryption: '',
			cipherText: '',
			deciphered: '',
			rowspan: 0,
			colspan: 0,
			rowspan_: 0,
			colspan_: 0,
			tableData: {},
			readonly: false,
			disableSetting: false,
			disableUpdate: true,
			matrix: {},
			matrixRev: {},
		}
	},
	computed:{
		originalTextLen () {
			return this.originalText.split(' ').join('').length
		},
		cipherTextLen () {
			return this.cipherText.split(' ').join('').length
		}
	},
	filters: {
		numberFilter (val) {
			val = parseInt(val)
			return val.toString(36).toUpperCase()
		}
	},
	mounted () {
		this.getMatrix55()
	},
	methods: {
		resetData () {
			this.rowspan = 0
			this.colspan = 0
			this.tableData = {}
		},
		// 加密
		encrypt () {
			this.originalText = this.originalText.split(' ').join('').toUpperCase()
			this.encryption = ''
			let conversion = ''
			for (let i = 0; i < this.originalTextLen; i++) {
				if (this.matrixRev[this.originalText[i]] === undefined) {
					this.$toast('该字符串与当前加密算法不匹配！')
					return
				}
				conversion += this.matrixRev[this.originalText[i]].split('_').map(v => this.transNumber(v)).join('')
			}
			this.encryption = conversion.toLowerCase()
		},
		// 解密
		decrypt () {
			this.cipherText = this.cipherText.split(' ').join('').toUpperCase()
			this.deciphered = ''
			let encode = this.cipherText
			let conversion = ''
			if (this.cipherTextLen % 2 != 0) {
				this.$toast('密文长度不正确！')
				return
			}
			for (let i = 0; i < this.cipherTextLen / 2; i++) {
				if (this.matrix[encode.substr(0,2)] === undefined) {
					this.$toast('该密文与当前加密算法不匹配！')
					return
				}
				conversion += this.matrix[encode.substr(0,2)]
				encode = encode.substring(2)
			}
			this.deciphered = conversion.toLowerCase()
		},
		getMatrix55 () {
			this.resetData()
			this.$nextTick(() => {
				this.rowspan = this.rowspan_ = 5
				this.colspan = this.colspan_ = 5
				this.tableData = this.$jstools.deepCopy(matrix55)
				this.readonly = true
				this.updateOptions()
			})
		},
		getMatrix94 () {
			this.resetData()
			this.$nextTick(() => {
				this.rowspan = this.rowspan_ = 9
				this.colspan = this.colspan_ = 4
				this.tableData = this.$jstools.deepCopy(matrix94)
				this.readonly = true
				this.updateOptions()
			})
		},
		// 创建表格
		createTable () {
			let tableData = {}
			let rowspan = parseInt(this.rowspan_)
			let colspan = parseInt(this.colspan_)
			if (rowspan <= 0 || rowspan > 35 || colspan <= 0 || colspan > 35) {
				this.$toast('行数和列数须在1~35范围内！')
				return
			}
			this.readonly = false
			this.disableSetting = true
			this.disableUpdate = false
			this.resetData()
			this.$nextTick(() => {
				this.rowspan = rowspan
				this.colspan = colspan
				for (let i = 1; i <= rowspan; i++) {
					for (let j = 1; j <= colspan; j++) {
						tableData[`${i}_${j}`] = ''
					}
				}
				this.tableData = tableData
			})
		},
		// 配置参数
		changeOptions () {
			this.readonly = false
			this.disableSetting = true
			this.disableUpdate = false
		},
		// 更新配置
		updateOptions () {
			let tableData = this.$jstools.deepCopy(this.tableData)
			this.matrix = {}
			this.matrixRev = {}
			this.readonly = true
			this.disableSetting = false
			this.disableUpdate = true
			for (let key in tableData) {
				let val = tableData[key].toUpperCase()
				this.matrix[key.split('_').map(v => this.transNumber(v)).join('')] = val
				if (/\//.test(val) && val.length > 1) {
					let vals = val.split('/')
					vals.forEach(v => {this.matrixRev[v] = key})
				} else {
					this.matrixRev[val] = key
				}
			}
		},
		transNumber (val) {
			val = parseInt(val)
			return val.toString(36).toUpperCase()
		}
	}
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
.page-matrix-decrypt {
	display: flex;
	flex-direction: column;
	.content {
		height: 0;
		flex-grow: 1;
		overflow: hidden auto;
		.col-form-label {
			text-align: right;
		}
		.panel-2 {
			margin-top: 1em;
			.alert {
				line-height: 2;
			}
			.table {
				margin-top: 1em;
				text-align: center;
				&.table-more {
					td {
						padding: .25rem;
						.form-control {
							padding: 0;
							font-size: 0.875rem;
						}
					}	
				}
			}
		}
	}
}
</style>
